#include "string.h"
#include "fmc_flash.h"



uint8_t write_fmc_flash(uint32_t adr, uint8_t * pdata , uint32_t len)
{
	uint32_t j;
	uint32_t pAdr;
	
	fmc_unlock();
	pAdr = adr;
	
	for (j = 0;j < len;j += 4)
	{

		fmc_word_program(pAdr, *(uint32_t*)pdata);
		if (*(uint32_t*)(pAdr) != *(uint32_t*)pdata)
		{
			return 1;
		}
		 pAdr += 4;
		 pdata += 4;
		 fmc_flag_clear(FMC_FLAG_END | FMC_FLAG_WPERR | FMC_FLAG_PGAERR | FMC_FLAG_PGERR );
	}
	fmc_lock();
	return 0;
}

//注意传入的指针必须是4的倍数
//返回0 成功，其它值失败
uint8_t read_fmc_flash(uint32_t adr, uint8_t * pdata , uint32_t len)
{
	uint32_t j;
	uint32_t pAdr = (uint32_t)adr;
	
	if ( (len % 4) != 0 )
	{
		return 1;
	}
	
	for (j = 0;j < len;j += 4)
	{
		*(uint32_t*)pdata = *(uint32_t*)pAdr;

		pAdr += 4;
		pdata += 4;
	}
	return 0;
}


/*
擦除一个page是1k，给出起始擦除地址，再给出要擦除的page数
*/
void erase_fmc_flash(uint32_t start_adr, uint32_t page_cnt)
{
	uint32_t i;
	
  /* unlock the flash program/erase controller */
  fmc_unlock();

  /* clear all pending flags */
  fmc_flag_clear(FMC_FLAG_END | FMC_FLAG_WPERR | FMC_FLAG_PGAERR | FMC_FLAG_PGERR);
		
	for (i = 0; i < page_cnt; i++)
	{
		/* erase the flash pages */
		fmc_page_erase(start_adr + i * FMC_PAGE_SIZE);
		fmc_flag_clear(FMC_FLAG_END | FMC_FLAG_WPERR | FMC_FLAG_PGAERR | FMC_FLAG_PGERR);		
	}
  

  /* lock the main FMC after the erase operation */
  fmc_lock();
}




//升级标记，返回1代表存在；返回0代表不存在
uint8_t chk_fmc_UpFlag(void)
{
	uint32_t *ptrd;
	uint32_t fileSize = 0;
	uint32_t fileSizeCheck = 0;
	
	ptrd = (uint32_t *)FMC_OTA_FLAG_PAGE_ADR;
	
	if((*ptrd) != FMC_OTA_Flag)
	{
		return 0;
	}
	
	ptrd = (uint32_t *)(FMC_OTA_FLAG_PAGE_ADR+4);
	fileSize = *ptrd;
	ptrd = (uint32_t *)(FMC_OTA_FLAG_PAGE_ADR+8);
	fileSizeCheck = *ptrd;
	fileSizeCheck = ~fileSizeCheck;
	
	if (fileSize != fileSizeCheck)
	{
		//校验失败
		fileSize = 0;
	}
	
	return 1;
	
}


//擦除升级标记
void eraseGD_fmc_UpFlag(void)
{

    /* unlock the flash program/erase controller */
    fmc_unlock();

    /* clear all pending flags */
    fmc_flag_clear(FMC_FLAG_END | FMC_FLAG_WPERR | FMC_FLAG_PGAERR | FMC_FLAG_PGERR);

    /* erase the flash pages */
		fmc_page_erase(FMC_OTA_FLAG_PAGE_ADR);
		fmc_flag_clear(FMC_FLAG_END | FMC_FLAG_WPERR | FMC_FLAG_PGAERR | FMC_FLAG_PGERR);

    /* lock the main FMC after the erase operation */
    fmc_lock();
}


//写升级标记，返回0代表成功，1失败
uint8_t writeGD_fmc_UpFlag(uint32_t fileSize)
{
	
	//写标记前要先擦除这一块，GD可能是4k一块
	eraseGD_fmc_UpFlag();
	
	/* unlock the flash program/erase controller */
	fmc_unlock();

	fmc_word_program(FMC_OTA_FLAG_PAGE_ADR, FMC_OTA_Flag);
	fmc_flag_clear(FMC_FLAG_END | FMC_FLAG_WPERR | FMC_FLAG_PGAERR | FMC_FLAG_PGERR );
	
	//把文件大小写入，再取反相当于一个校验
	fmc_word_program(FMC_OTA_FLAG_PAGE_ADR+4, fileSize);
	fmc_flag_clear(FMC_FLAG_END | FMC_FLAG_WPERR | FMC_FLAG_PGAERR | FMC_FLAG_PGERR );
	
	fmc_word_program(FMC_OTA_FLAG_PAGE_ADR+8, ~fileSize);
	fmc_flag_clear(FMC_FLAG_END | FMC_FLAG_WPERR | FMC_FLAG_PGAERR | FMC_FLAG_PGERR );
	

	/* lock the main FMC after the program operation */
	fmc_lock();
	
	return 0;
}




/*
计算异或校验
*/
uint8_t get_chk_xorForFlash(uint8_t * da, uint16_t len)
{
	uint8_t xorr;
	uint16_t i;
	xorr = 0;
	for (i=0;i<len;i++)
	{
		xorr ^= da[i];
	}

	return xorr;
}



/*
存指定长度参数，1024
注意保存和提取长度要一样
返回0保存参数成功
返回1保存失败
*/
uint8_t savePara1024WithAdr(uint32_t adr, uint8_t *para, uint16_t len)
{
	uint8_t DaWr[4];
	uint8_t DaRd[1200];
	
	uint8_t i, chkXor;
	
	if (len > 1024)
	{
		return 1;
	}
	
	DaWr[0] = 0xA0;	//标记
	DaWr[1] = 0xA1;	//标记
	DaWr[2] = 0xA2;	//标记
	DaWr[3] = get_chk_xorForFlash(para, len);
	chkXor = DaWr[3];
	
	for (i=0;i<3;i++)
	{
		erase_fmc_flash(adr, 1);

		write_fmc_flash(adr, DaWr, 4);
		write_fmc_flash(adr+4, para, len);
		//write_fmc_flash(adr+2+len, DaWr+2, 1);
		
		read_fmc_flash(adr, DaRd, len+4);
		
		if ( (memcmp(DaRd+4, para, len) == 0) && 
				(DaRd[0] == 0xA0) &&
				(DaRd[1] == 0xA1) &&
				(DaRd[2] == 0xA2) &&
				(DaRd[3] == chkXor) )
		{
			return 0;
		}
	}

	return 1;
}

/*
取指定长度参数，最大512
注意保存和提取长度要一样
返回0读取参数成功
返回1失败
*/
uint8_t readPara1024WithAdr(uint32_t adr, uint8_t * pPara, uint16_t len)
{
	uint8_t DaRd[1200];

	uint8_t i, chkXor;
	
	//uint16_t lenRd;
	
	if (len > 1024)
	{
		return 1;
	}
	
	for (i=0;i<3;i++)
	{
		
		read_fmc_flash(adr, DaRd, len+4);
		
		chkXor = get_chk_xorForFlash(DaRd+4, len);
		if ( (DaRd[0] == 0xA0) &&
				(DaRd[1] == 0xA1) &&
				(DaRd[2] == 0xA2) &&
				(DaRd[3] == chkXor) )
		{
			memcpy(pPara, DaRd+4, len);
			return 0;
		}
	}

	return 1;
}



